package fsmsim.kernel;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.QuadCurve2D;
import java.util.ArrayList;

public abstract class Transicion {
	Estado _origen,_destino;
	char _movimiento, _readCinta,_writeCinta,_readPila,_writePila;
	float _angulo;
	int _distancia;
	int [][] _tri;
	ArrayList<QuadCurve2D.Float>  _curvas= new ArrayList<QuadCurve2D.Float>();
	Point _centro;
	public Transicion(Estado origen, Estado destino, char leerCinta,char escribirCinta,char leerPila, char escribirPila,char movimiento){
		_origen= origen;
		_destino=destino;
		_movimiento=movimiento;
		_readCinta = leerCinta;
		_writeCinta= escribirCinta;
		_readPila= leerPila;
		_writePila= escribirPila;
		_tri=new int[2][3];
		_angulo=(float) Math.PI;
		_distancia=0;
		updateLocation();
	}
	
	public void Draw(Graphics2D g2){
		Draw(g2, Color.BLUE,Color.BLACK);
	}
	public void Draw(Graphics2D g2, Color color1,Color color2){
		Color c=g2.getColor();
		g2.setColor(color1);
		for(QuadCurve2D.Float curva:_curvas)
			g2.draw(curva);
        g2.fillPolygon(_tri[0],_tri[1],3   );
        g2.setColor(color2);
        g2.drawString(toString(), _centro.x, _centro.y-10);
        g2.setColor(c);
	}

	public void updateLocation(Point punto){
		int dx=punto.x-_origen.getX();
	    int dy=punto.y-_origen.getY();
	    if(_origen==_destino){
	        _distancia=(int) Math.sqrt(dx*dx+dy*dy);
	        _angulo= (float)(Math.atan((float)dy/(float)dx));
	        if(dx<0) {
	        	_angulo+=Math.PI;
	        }
	    }else{
	        double angB=Math.atan((float)(punto.x-_origen.getX())/(float)(punto.y-_origen.getY()));
	        double angA=Math.atan((float)(_destino.getX()-_origen.getX())/(float)(_destino.getY()-_origen.getY()));
	        if(angB<angA){
	            _distancia=(int) (Math.sqrt(dx * dx + dy * dy) * Math.sin((angA - angB)));
	        }else{
	            _distancia=(int) (Math.sqrt(dx * dx + dy * dy) * Math.sin((angA + Math.PI - angB)));
	        }
	    }
	    updateLocation();
	}
	public void updateLocation(){
		Point medio=new Point( (_origen.getX()+_destino.getX()) /2 , (_origen.getY()+_destino.getY())/2 );
		_curvas.clear();
        int dx=0,dy=0;
        if(_origen==_destino){
        	dx= (int) (Math.cos(_angulo)*_distancia);
        	dy= (int) (Math.sin(_angulo)*_distancia);
            _centro=new Point( medio.x+dx,medio.y+dy);
            
            medio= new Point( (_origen.getX()+_centro.x) /2 , (_origen.getY()+_centro.y)/2 );
            int dxx=(int) (Math.cos(_angulo+Math.PI/2)*_distancia/2);
            int dyy=(int) (Math.sin(_angulo+Math.PI/2)*_distancia/2);
            
            Point pm1= new Point (medio.x+dxx,medio.y+dyy);
            Point pm2= new Point (medio.x-dxx, medio.y-dyy);
            
            Point pm11= new Point (pm1.x+dx/2,pm1.y+dy/2);
            Point pm12=new Point (pm1.x-dx/2, pm1.y-dy/2);
            Point pm21= new Point(pm2.x+dx/2,pm2.y+dy/2);
            Point pm22= new Point(pm2.x-dx/2,pm2.y-dy/2);
            
            _curvas.add( new QuadCurve2D.Float(_origen.getX(),_origen.getY(), pm12.x,pm12.y, pm1.x,pm1.y));
            _curvas.add(new QuadCurve2D.Float( pm1.x,pm1.y,pm11.x,pm11.y,_centro.x,_centro.y  ));
            _curvas.add(new QuadCurve2D.Float(_origen.getX(),_origen.getY(), pm22.x,pm22.y,pm2.x,pm2.y));
            _curvas.add(new QuadCurve2D.Float(_centro.x,_centro.y, pm21.x,pm21.y,pm2.x,pm2.y));
            
            float ang=(float) (_angulo+Math.PI/2);;
            _tri[0][0]=_centro.x+ (int)(Math.cos(ang-Math.PI/2)*7 );
            _tri[1][0]=_centro.y+ (int)(Math.sin(ang-Math.PI/2)*7);
            _tri[0][1]=_centro.x+ (int)(Math.cos(ang)*7);
            _tri[1][1]=_centro.y+ (int)(Math.sin(ang)*7);
            _tri[0][2]=_centro.x+ (int)(Math.cos(ang+Math.PI/2)*7);
            _tri[1][2]=_centro.y+ (int)(Math.sin(ang+Math.PI/2)*7);
        }else{
        	dx=(-_origen.getX()+_destino.getX());
            dy=(-_origen.getY()+_destino.getY());
            _angulo=(float) (Math.atan( (float)dy/(float)dx)+Math.PI/2);
            if(dx<0){
                _angulo+=Math.PI;
            }
            dx=(int)(Math.cos(_angulo)*_distancia);
            dy=(int)(Math.sin(_angulo)*_distancia);
            _centro=new Point(medio.x- dx,medio.y-dy);
            Point c1=new Point(_origen.getX()- dx,_origen.getY()-dy);
            Point c2=new Point(_destino.getX()- dx,_destino.getY()-dy);
            _curvas.add(new QuadCurve2D.Float( _origen.getX(),_origen.getY(),c1.x,c1.y,_centro.x,_centro.y ) );
            _curvas.add(new QuadCurve2D.Float( _destino.getX(),_destino.getY(),c2.x,c2.y,_centro.x,_centro.y ) );
            float ang=(float) (_angulo-Math.PI/2);;
            _tri[0][0]=_centro.x+ (int)(Math.cos(ang-Math.PI/2)*7 );
            _tri[1][0]=_centro.y+ (int)(Math.sin(ang-Math.PI/2)*7);
            _tri[0][1]=_centro.x+ (int)(Math.cos(ang)*7);
            _tri[1][1]=_centro.y+ (int)(Math.sin(ang)*7);
            _tri[0][2]=_centro.x+ (int)(Math.cos(ang+Math.PI/2)*7);
            _tri[1][2]=_centro.y+ (int)(Math.sin(ang+Math.PI/2)*7);
        }
	}
	
	public Estado getOrigen(){
		return _origen;
	}
	public Estado getDestino(){
		return _destino;
	}
	public char getMovimiento() {
		return _movimiento;
	}
	public float getAngulo() {
		return _angulo;
	}
	public int getDistancia() {
		return _distancia;
	}
	public char getLecturaCinta() {
		return _readCinta;
	}
	public char getEscrituraCinta() {
		return _writeCinta;
	}
	public char getLecturaPila() {
		return _readPila;
	}
	public char getEscrituraPila() {
		return _writePila;
	}
	
	public int getX(){
		return _centro.x;
	}
	public int getY(){
		return _centro.y;
	}
	
}
